/* 
 * lab4.cpp
 *
 * Template application for Procedural Shading textures lab.
 *
 */

#include <math.h>
#include <assert.h>

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include "ShaderSetup.h"

#include <stdio.h>

#define	bool	int
#define	false	0
#define	true	1

int	currentX;		// Current location of X
int	currentY;		// Current location of Y
int	startX;			// Starting location of X
int	startY;			// Starting location of Y
int	windowHeight;		// Current height of window
int	windowWidth;		// Current width of window

// handle for our shader
GLuint texShader;

// handle for our texture
GLuint textureID;

// Scene will mimic the basic scene used in RenderMan exercises
//  Vertices and colors for drawing the objects in the scene
GLfloat WallColors[][3] = {
    { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, { 1.0, 0.0, 0.0 }, 
    { 1.0, 0.0, 0.0 }
};

GLfloat WallVertices[][3] = {
    { -5.0,  5.0,  0.0 }, {  5.0, 5.0,  0.0 }, { 5.0,  -5.0,  0.0 }, 
    { -5.0,  -5.0,  0.0 }
};

GLfloat WallTexCoords[][2] = {
    { 0.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 0.0 } 
};

GLfloat FloorColors[][3] = {
    { 1.0, 1.0, 0.5 }, { 1.0, 1.0, 0.5 }, { 1.0, 1.0, 0.5 }, 
    { 1.0, 1.0, 0.5 }
};

GLfloat FloorVertices[][3] = {
    { -5.0, -5.0,  5.0 }, {  5.0, -5.0,  5.0 }, { 5.0,  -5.0,  -5.0 }, 
    { -5.0, -5.0, -5.0 }
};

GLUquadricObj *sphere = NULL;


// Some global material properties
GLfloat no_mat[]            = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_ambient[]       = { 0.7, 0.7, 0.1, 1.0 };
GLfloat mat_ambient_color[] = { 0.5, 0.5, 0.05, 1.0 };
GLfloat mat_diffuse[]       = { 0.5, 0.5, 0.05, 1.0 };
GLfloat mat_specular[]      = { 0.8, 0.8, 0.8, 1.0 };
GLfloat no_shininess[]      = { 0.0 };
GLfloat low_shininess[]     = { 5.0 };
GLfloat high_shininess[]    = { 100.0 };
GLfloat mat_emission[]      = { 0.3, 0.2, 0.2, 0.0 };


/*
 *  The function draws your scene.  It will also apply the shader and attach
 *  it to the correct primitive.  For sake of the example, the shader will
 *  be applied to the floor.
 */

void drawscene( void ) {

	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	// The next 3 calls prepare the texture for use in the shader
//	glEnable  (GL_TEXTURE_2D);
//	glActiveTexture (GL_TEXTURE0);
//	glBindTexture (GL_TEXTURE_2D, textureID);
	
	// Insert code here to use your shader and set the uniform 
	// variable for the texture
//	glUseProgram (texShader);
//      GLuint texloc = glGetUniformLocation (texShader, "texID");
//      glUniform1i (texloc, 0);

	// draw the wall - don't forget to assign your texture coord
	glBegin( GL_QUADS );

	  glColor3fv(  WallColors[0]   );
	  glNormal3f( 0.0, 0.0, -1.0);
	  glTexCoord2fv ( WallTexCoords[0] );
	  glVertex3fv( WallVertices[0] );

	  glColor3fv(  WallColors[1]   );
	  glNormal3f( 0.0, 0.0, -1.0);
	  glTexCoord2fv ( WallTexCoords[1] );
	  glVertex3fv( WallVertices[1] );

	  glColor3fv(  WallColors[2]   );
	  glNormal3f( 0.0, 0.0, -1.0);
	  glTexCoord2fv ( WallTexCoords[2] );
	  glVertex3fv( WallVertices[2] );

	  glColor3fv(  WallColors[3]   );
	  glNormal3f( 0.0, 0.0, -1.0);
	  glTexCoord2fv ( WallTexCoords[3] );
	  glVertex3fv( WallVertices[3] );

	glEnd( );

	// draw your floor
	glBegin( GL_POLYGON );

	  glColor3fv(  FloorColors[0]   );
	  glTexCoord2f (0.0, 0.0);
	  glVertex3fv( FloorVertices[0] );

	  glColor3fv(  FloorColors[1]   );
	  glTexCoord2f (0.0, 1.0);
	  glVertex3fv( FloorVertices[1] );

	  glColor3fv(  FloorColors[2]   );
	  glTexCoord2f (1.0, 1.0);
	  glVertex3fv( FloorVertices[2] );

	  glColor3fv(  FloorColors[3]   );
	  glTexCoord2f (1.0, 0.0);
	  glVertex3fv( FloorVertices[3] );

	glEnd( );

#ifdef image_includes_sphere
//
// by default, do not include the sphere
//

	// draw the sphere
	if (!sphere) {
		sphere = gluNewQuadric();
		gluQuadricDrawStyle(sphere, GLU_FILL);
	}

	glPushMatrix();
	  glTranslatef (0.0, 0.0, -2.0);

	  // Apply material properties here and then use your shader
	  // program.
	  glMaterialfv( GL_FRONT, GL_AMBIENT,   mat_ambient_color );
	  glMaterialfv( GL_FRONT, GL_DIFFUSE,   mat_diffuse );
	  glMaterialfv( GL_FRONT, GL_SPECULAR,  mat_specular );
	  glMaterialfv( GL_FRONT, GL_SHININESS, high_shininess );
	  glMaterialfv( GL_FRONT, GL_EMISSION,  no_mat );		

	  gluSphere (sphere, 2, 100, 100);
	glPopMatrix();
#endif

}

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Display callback function - used for redisplay as well
 */

void display( void ) {

	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	drawscene();

	glutSwapBuffers();

}



/*
 * Callback function for screen window resizing/reshaping
 */

void myReshape( int width, int height ) {

	glViewport( 0, 0, width, height );
	windowWidth = width;
	windowHeight = height;

}


/*
 * Callback function for keyboard input
 *
 * Ignores all input except 'q', 'Q', and ESC
 */

void keyboard( unsigned char key, int x, int y ) {

	switch( key ) {

		case 'q': case 'Q': case 033:
			exit( EXIT_SUCCESS );
	
	}

}

#ifdef __cplusplus
}
#endif



/*
 *  OpenGL initialization
 */

void init( void ) {

	GLfloat ambient[]        = { 0.2, 0.2, 0.2, 1.0 };
	GLfloat diffuse[]        = { 1.0, 1.0, 1.0, 1.0 };
	GLfloat specular[]       = { 1.0, 1.0, 1.0, 1.0 };
	GLfloat position[]       = { 0.0, 10.0, -8.0, 0.0 };
	GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 1.0 };
	GLfloat local_view[]     = { 0.0 };

	glClearColor( 0.0, 0.1, 0.1, 0.0 );

	// enable depth testing
	glEnable( GL_DEPTH_TEST );
	glEnable (GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

	// some basic lighting setup
	glLightfv( GL_LIGHT0, GL_AMBIENT, ambient );
	glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse );
	glLightfv( GL_LIGHT0, GL_POSITION, position );
	glLightModelfv( GL_LIGHT_MODEL_AMBIENT, lmodel_ambient );
	glLightModelfv( GL_LIGHT_MODEL_LOCAL_VIEWER, local_view );

	glEnable( GL_LIGHTING );
	glEnable( GL_LIGHT0 );

	// Camera stuff - matrix initialization
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	gluPerspective (45, 1.0, 1.0, 100.0);

	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity( );
	gluLookAt (0.0, 15.0, -15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	// set up your shaders with code like this:
	//
	// GLuint errors;
	// x = ShaderSetup( "vertfile", "fragfile", &errors );
	// if( errors != E_NO_ERROR ) {
	//	fprintf( stderr, "Error in shader setup - %s\n",
	//		 ErrorString(errors) );
	//	exit( 1 );
        // }

}


/*
 * Main routine - GLUT setup and initialization
 */

int main( int argc, char **argv ) {

	// Initialize GLUT
	glutInit( &argc, argv );

	// Enable double buffering and depth buffering
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
	glutInitWindowSize( 500, 500 );
	glutCreateWindow( argv[0] );

	// Callback functions are specified 
	glutReshapeFunc( myReshape );
	glutDisplayFunc( display );
	glutKeyboardFunc( keyboard );

	// Do OpenGL initialization
	init();
	
	// set up stuff for noise
	glEnable(GL_TEXTURE_1D); // Enable 1D texturing
	glEnable(GL_TEXTURE_2D); // Enable 2D texturing

	// enter your display loop.
	glutMainLoop();
	
	return 0;
}
